<?php

  /**
   * User
   *
   * ORM для таблицы зарегистрированных пользователей
   *
   * @property      int          $id             идентификатор
   * @property      string       $login          логин
   * @property      string       $paswd          пароль
   * @property      string       $name           имя
   * @property      string       $about          информация о себе
   * @property      string       $sex            пол ('male','female')
   * @property      string       $birthday       дата рождения
   * @property      string       $hometown       родной город
   * @property      string       $now_live       место проживания
   * @property      string       $education      образование
   * @property      string       $sstatus        социальный статус
   * @property      string       $mstatus        семейное положение
   * @property      string       $politics       политические убеждения
   * @property      string       $religion       религиозные взгляды
   * @property      string       $ps             постскриптум
   * @property      string       $email          адрес электропочты
   * @property      string       $phone          телефон
   * @property      int          $icq            номер ICQ
   * @property      string       $jabber         jabber-аккаунт
   * @property      string       $skype          skype-аккаунт
   * @property      string       $twitter        twitter-аккаунт
   * @property      string       $facebook       facebook-аккаунт
   * @property      string       $vkontakte      аккаунт ВКонтакте
   * @property      string       $myworld        аккаунт в Мой Мир
   * @property      string       $livejournal    аккаунт в ЖЖ
   * @property      string       $public         общедоступная информация
   * @property      string       $photo          имя файла-аватара
   * @property      string       $photo_type     тип аватара
   * @property      string       $activate_code  код активации учетной записи
   * @property      int          $category_id    идентификатор категории автора
   * @property      int          $is_mod         признак модератора
   * @property-read Category     $category       категория автора
   * @property-read Post[]       $posts          опубликованные посты
   * @property-read Comment[]    $comments       оставленные комменты
   * @property-read Evaluation[] $evaluation     выставленные баллы
   * @property-read Authority[]  $authority      выставленные оценки
   * @property-read string       $role           роль на сайте
   * @property-read string[]     $publicSet      статусы публикации контактных данных
   * @property-read int          $balls          суммарное количество баллов за посты
   * @property-read int          $authorityLevel уровень авторитетности
   * @property-read string       $group          группа
   * @property-read string       $frm_birthday   текст, содержащий дату рождения
   * @method User auth()   выборка активированных учетных записей
   * @method User autors() выборка авторов
   */

  final class User extends Record
  {
  // роли на сайте
    const GUEST     = "guest";
    const USER      = "user";
    const AUTOR     = "autor";
    const MODERATOR = "moderator";

  // типы аватара
    const AVA_PHOTO  = "photo";
    const AVA_AVATAR = "avatar";

  // имя папки с фотографиями
    const PHOTOS = "photos";

    /**
     * подтверждение пароля
     *
     * @var string
     */
    public $confirm;

    /**
     * вернуть экземпляр модели
     *
     * @return User
     * @access public
     */
    public static function model($className = __CLASS__)
    {
      return parent::model($className);
    }

    /**
     * отображаемые названия атрибутов модели
     *
     * @return string[]
     * @access public
     */
    public function attributeLabels()
    {
      return array(
        "photo"   => "Фотография",
        "name"    => "Имя",
        "login"   => "Логин",
        "paswd"   => "Пароль",
        "confirm" => "Повтор&nbsp;пароля",
        "email"   => "e-mail"
      );
    }

    /**
     * правила проверки атрибутов модели
     *
     * @return array[]
     * @access public
     */
    public function rules()
    {
      return array(
        array("id", "exist", "className" => "User", "allowEmpty" => false, "on" => "update"),
        array("login", "required", "message" => "Укажите свой логин"),
        array("login", "length", "max" => $this->fieldSize("login"), "encoding" => "utf-8", "skipOnError" => true),
        array("login", "match", "message" => "Логин должен содержать только буквы латинского алфавита, цифры, знаки \"_\" и \"-\"", "pattern" => "/^[\w\-]+$/"),
        array("login", "unique", "message" => "Логин уже занят", "className" => "User", "caseSensitive" => false),
        array("paswd", "required", "message" => "Укажите свой пароль", "on" => "insert"),
        array("paswd", "required", "message" => "Укажите новый пароль", "on" => "update"),
        array("confirm", "compare", "message" => "Пароли не совпадают", "compareAttribute" => "paswd"),
        array("name", "required", "message" => "Укажите свое имя"),
        array("name", "length", "max" => $this->fieldSize("name"), "encoding" => "utf-8", "skipOnError" => true),
        array("about,ps,public,activate_code,is_mod", "safe"),
        array("sex", "in", "range" => $this->enum("sex"), "skipOnError" => true),
        array("birthday", "match", "message" => "Некорректная дата", "pattern" => "/^\d{4}\-\d{2}\-\d{2}$/"),
        array("hometown,now_live", "length", "max" => 40, "encoding" => "utf-8", "skipOnError" => true),
        array("sstatus,mstatus,politics,religion", "length", "max" => 80, "encoding" => "utf-8", "skipOnError" => true),
        array("email", "required", "message" => "Укажите свой e-mail"),
        array("email", "email", "message" => "E-mail указан неверно"),
        array("email,jabber,skype,twitter,facebook,vkontakte,myworld,livejournal,education,photo", "length", "max" => 255, "encoding" => "utf-8", "skipOnError" => true),
        array("phone", "match", "message" => "Некорректный номер телефона", "pattern" => "/^(((\+?(\d{1,4}|\d-\d{1,3})[\s-]?)?(\(\d{3}\)|\d{3}))?(\d{3}([\s-]?\d{2}){2}|\d{2}[\s-]?\d{3}[\s-]?\d{2}|(\d{2}[\s-]?){2}\d{3})|((\+?\d{1,3}[\s-]?)?(\(\d{4}\)|\d{4}))?(\d{2}[\s-]?){2}\d{2}|((\+?\d{1,3}[\s-]?)?(\(\d{5}\)|\d{5}))?(\d([\s-]?\d{2}){2}|\d{2}[\s-]?\d[\s-]?\d{2}|(\d{2}[\s-]?){2}\d))$/"),
        array("icq", "match", "message" => "UIN должен состоять из 6-9 цифр", "pattern" => "/^\d{6,9}$/"),
        array("jabber", "email", "message" => "Jabber-аккаунт указан неверно"),
        array("skype", "match", "message" => "Имя skype должно начинаться с буквы<br />латинского алфавита и содержать от 6 до 32 символов<br />(только буквы латинского алфавита и цифры)", "pattern" => "/^[a-zA-Z][a-zA-Z\d]{5,31}$/"),
        array("twitter", "match", "message" => "Требуется url вида http://twitter.com/username", "pattern" => "/^((http:\/\/)?(www\.)?twitter\.com\/)?(\w+)$/"),
        array("facebook", "match", "message" => "Требуется url вида http://facebook.com/username", "pattern" => "/^((http:\/\/)?(www\.)?facebook\.com\/)?(\w+)$/"),
        array("vkontakte", "match", "message" => "Требуется url вида http://vkontakte.ru/username", "pattern" => "/^((http:\/\/)?(www\.)?vkontakte\.ru\/)?(\w+)$/"),
        array("vkontakte", "unique", "message" => "Аккаунт ВКонтакте связан с другим пользователем", "className" => "User", "caseSensitive" => false),
        array("myworld", "match", "message" => "Требуется url вида http://my.mail.ru/mail/username", "pattern" => "/^((http:\/\/)?(www\.)?my\.mail\.ru\/mail\/)?(\w+)$/"),
        array("livejournal", "match", "message" => "Требуется url вида http://username.livejournal.com", "pattern" => "/^(http:\/\/)?(\w+)(\.livejournal\.com\/?)?$/"),
        array("photo_type", "in", "range" => $this->enum("photo_type"), "skipOnError" => true),
        array("category_id", "exist", "className" => "Category", "skipOnError" => true)
      ) + parent::rules();
    }

    /**
     * действия перед проверкой
     *
     * @return bool
     * @access protected
     */
    protected function beforeValidate()
    {
      if ($success = parent::beforeValidate())
      {
        $this->name = strip_tags($this->name);
        if (!$this->vkontakte)
          $this->vkontakte = null;
      }

      return $success;
    }

    /**
     * действия после проверки
     *
     * @return void
     * @access protected
     */
    protected function afterValidate()
    {
      parent::afterValidate();

      $this->unsetAttributes(array("confirm"));
    }

    /**
     * параметры выборки
     *
     * @return array[]
     * @access public
     */
    public function defaultScope()
    {
      return array("order" => "`name`") + parent::defaultScope();
    }

    /**
     * наборы фильтров для выборки
     *
     * @return array[]
     * @access public
     */
    public function scopes()
    {
      return array(
        "auth"   => array("condition" => "`activate_code` is null"),
        "autors" => array("condition" => "not(`category_id` is null or `category_id`='0')")
      ) + parent::scopes();
    }

    /**
     * связи с другими таблицами
     *
     * @return array[]
     * @access public
     */
    public function relations()
    {
      return array(
        "category"   => array(self::BELONGS_TO, "Category", "category_id"),
        "posts"      => array(self::HAS_MANY, "Post", "user_id"),
        "comments"   => array(self::HAS_MANY, "Comment", "user_id"),
        "evaluation" => array(self::HAS_MANY, "Evaluation", "user_id"),
        "authority"  => array(self::HAS_MANY, "Authority", "user_id")
      ) + parent::relations();
    }

    /**
     * действия перед сохранением
     *
     * @return bool
     * @access protected
     */
    protected function beforeSave()
    {
      if ($success = parent::beforeSave())
        if ($this->isNewRecord)
        {
          $this->paswd         = md5($this->paswd);
          $this->activate_code = md5($_SERVER["REMOTE_ADDR"].$_SERVER["HTTP_USER_AGENT"].mktime());

          if ($photo = $this->photo)
            if (strcasecmp($this->photo_type, self::AVA_PHOTO))
              $this->photo = basename($photo);
            else
            {
              $path     = WebApplication::createPath(array($this->app->contentPath, ContentController::IMG_FULL, self::PHOTOS));
              $tmpname  = tempnam($path, self::AVA_PHOTO);
              $filename = "$tmpname.".pathinfo($photo, PATHINFO_EXTENSION);
              @unlink($tmpname);
              $tmpname  = WebApplication::createPath(array($path, $photo));

              if ($src = ContentController::getThumb($tmpname))
              {
                call_user_func("image$src[type]", $src["image"], $filename);
                imagedestroy($src["image"]);
                $this->photo = basename($filename);
                @unlink($tmpname);
              }
              else
                $this->unsetAttributes("photo", "photo_type");
            }
          else
            $this->photo = $this->photo_type = null;
        }

      return $success;
    }

    /**
     * действия перед удалением
     *
     * @return bool
     * @access protected
     */
    protected function beforeDelete()
    {
      if ($success = parent::beforeDelete())
      {
        $this->removePhoto();

        foreach ($this->posts as $post)
          $post->delete();
        foreach ($this->comments as $comment)
          $comment->delete();

        $attrs = array("user_id" => $this->id);
        Authority::model()->deleteAllByAttributes($attrs);
        Evaluation::model()->deleteAllByAttributes($attrs);
      }

      return $success;
    }

    /**
     * удалить изображение
     *
     * @return void
     * @access public
     */
    public function removePhoto()
    {
      if (($photo = $this->photo) && !strcasecmp($this->photo_type, self::AVA_PHOTO) && !$this->exists("`photo`='$photo' and `photo_type`='".self::AVA_PHOTO."' and `id`!='$this->id'"))
        ContentController::imgRemove(self::PHOTOS, $photo);
    }

    /**
     * вернуть роль на сайте
     *
     * @return string
     * @access public
     */
    public function getRole()
    {
      return $this->is_mod ? self::MODERATOR : ($this->category_id ? self::AUTOR : self::USER);
    }

    /**
     * вернуть статусы публикации контактных данных
     *
     * @return string[]
     * @access public
     */
    public function getPublicSet()
    {
      $set = $this->public;
      return $set ? explode(",", $set) : array();
    }

    /**
     * вернуть умолчательное изображение
     *
     * @param string $type тип изображения
     * @return string
     * @access public
     */
    public static function getDefaultAvatar($type = ContentController::IMG_FULL)
    {
      return Yii::app()->contentUrl."/$type/".self::PHOTOS."/avatar.jpg";
    }

    /**
     * вернуть URL изображения
     *
     * @param string $type тип изображения
     * @return string
     * @access public
     */
    public function getAvatar($type = ContentController::IMG_FULL)
    {
      $photo = $this->photo;
      return $photo ? "{$this->app->contentUrl}/$type/{$this->photo_type}s/$photo" : self::getDefaultAvatar($type);
    }

    /**
     * вернуть URL для контактных данных
     *
     * @param string $field имя поля
     * @return string
     * @access public
     */
    public function getAccountUrl($field)
    {
      static $links = array(
        "email"       => "mailto:%s",
        "phone"       => "callto:%s",
        "twitter"     => "http://twitter.com/%s",
        "facebook"    => "http://facebook.com/%s",
        "vkontakte"   => "http://vkontakte.ru/%s",
        "myworld"     => "http://my.mail.ru/mail/%s",
        "livejournal" => "http://%s.livejournal.com"
      );

      if ($links[$field] && ($value = $this->$field))
      {
        $rules = $this->rules();
        $rule  = null;
        while (!$rule && ($r = each($rules)))
          if (!strcasecmp($r["value"][0], $field))
            $rule = $r["value"];
        if ($rule)
        {
          if (!strcasecmp($rule[1], "match"))
            $value = preg_replace($rule["pattern"], "$".(strcasecmp($field, "livejournal") ? 4 : 2), $value);
          return sprintf($links[$field], $value);
        }
      }
      return "";
    }

    /**
     * вернуть суммарное кол-во баллов за посты
     *
     * @return int
     * @access public
     */
    public function getBalls()
    {
      $balls = 0;

      foreach ($this->posts as $post)
        $balls += $post->balls;

      return $balls;
    }

    /**
     * вернуть уровень авторитетности пользователя
     *
     * @return int
     * @access public
     */
    public function getAuthorityLevel()
    {
      $a = 0;

      foreach ($this->posts as $post)
        $a += $post->authorityLevel;
      foreach ($this->comments as $comment)
        $a += $comment->authorityLevel;

      return $a;
    }

    /**
     * вернуть список групп
     *
     * @return string[]
     * @access public
     */
    public static function groups()
    {
      return array(
        250 => "гигант мысли",
        180 => "профессор",
        120 => "бакалавр",
         70 => "студент",
         30 => "школяр",
          0 => "младшая группа"
      );
    }

    /**
     * вернуть группу пользователя
     *
     * @return string
     * @access public
     */
    public function getGroup()
    {
      $a = $this->authorityLevel;

      foreach (self::groups() as $score => $group)
        if ($score <= $a)
          return $group;
    }

    /**
     * вернуть форматированную дату рождения
     *
     * @return string
     * @access public
     */
    public function getFrm_birthday()
    {
      $frm = $this->birthday;
      return $frm ? $this->app->frmDate($frm) : "";
    }
  }

?>
